﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using libtcodWrapper;
using Console = libtcodWrapper.Console;

namespace HDHack
{
    class Level
    {        
        Player p;
        List<Monster> mlist = new List<Monster>();
        List<Terrain> tList = new List<Terrain>();
        List<Item> iList = new List<Item>();

        //Temp hardcoding of items
        MeleeWeapon w1 = new MeleeWeapon(1, 1, "Paper Cutter Blade", ')', 2);
        MeleeWeapon w2 = new MeleeWeapon(1, 1, "Paper Cutter Blade", ')', 2);


        public bool MapVisible = false;

        public DownStairs dStairs;
        public UpStairs uStairs;

        public int LevelIndex;

        public Tile[,] tiles;
        public float TORCH_RADIUS = 10.0f;
        public float SQUARED_TORCH_RADIUS;

        public bool recomputeFov = true; // the pDungeon.pProgram.player moved. must recompute fov
        public bool torch = false; // torch fx on ?
        public bool light_walls = true;
        public string[] smap;
        public List<Tile> OpenMonsterTiles = new List<Tile>();
        public List<Tile> OpenItemTiles = new List<Tile>();
        public List<Tile> OpenPersonTiles = new List<Tile>();
        public List<Tile> OpenTerrainTiles = new List<Tile>();
        TCODFov map;

        //Color darkWall = Color.FromRGB(0, 0, 0);
        //Color darkGround = Color.FromRGB(0, 0, 0);
        Color darkWall = Color.FromRGB(0, 0, 100);
        Color seenWall = Color.FromRGB(0, 0, 100);
        Color lightWall = Color.FromRGB(130, 110, 50);
        Color darkGround = Color.FromRGB(50, 50, 150);
        Color seenGround = Color.FromRGB(50, 50, 150);
        Color lightGround = Color.FromRGB(200, 180, 50);

        Dungeon pDungeon;

        TCODNoise map_noise;
        public float torchx = 0.0f; // torch light position in the perlin noise

        public int algonum = 0;
        string[] algo_names = { "BASIC      ", "DIAMOND    ", "SHADOW     ", 
		                        "PERMISSIVE0","PERMISSIVE1","PERMISSIVE2","PERMISSIVE3","PERMISSIVE4",
		                        "PERMISSIVE5","PERMISSIVE6","PERMISSIVE7","PERMISSIVE8" };

        public TCODPathFinding path = null;
        public bool recalculatePath = false;




        #region Map
        /*string[] smap = {
        "##############################################",
        "#######################      #################",
        "#####################    #     ###############",
        "######################  ###        ###########",
        "##################      #####             ####",
        "################       ########    ###### ####",
        "###############      #################### ####",
        "################    ######                  ##",
        "########   #######  ######   #     #     #  ##",
        "########   ######      ###                  ##",
        "########                                    ##",
        "####       ######      ###   #     #     #  ##",
        "#### ###   ########## ####                  ##",
        "#### ###   ##########   ###########=##########",
        "#### ##################   #####          #####",
        "#### ###             #### #####          #####",
        "####           #     ####                #####",
        "########       #     #### #####          #####",
        "########       #####      ####################",
        "##############################################"
        };*/

        #endregion


        public Level(Dungeon pd, int levelindex)
        {

            pDungeon = pd;

            iList.Add(w1);
            iList.Add(w2);

            LevelIndex = levelindex;
            if (LevelIndex > 0 && LevelIndex < (pDungeon.size - 1))
            {
                uStairs = new UpStairs();
                dStairs = new DownStairs();
                tList.Add(uStairs);
                tList.Add(dStairs);

            }
            else if (LevelIndex == (pDungeon.size - 1))
            {
                uStairs = new UpStairs();
                tList.Add(uStairs);
            }
            else if (LevelIndex == 0)
            {
                dStairs = new DownStairs();
                tList.Add(dStairs);
            }

            LevelGenerator lg = new LevelGenerator(Program.MAP_SCREEN_HEIGHT, Program.MAP_SCREEN_WIDTH);
            char[,] tmap = lg.GenerateLevel();
            smap = ConvertMap(tmap);
            
            SQUARED_TORCH_RADIUS = (TORCH_RADIUS * TORCH_RADIUS);
            tiles = new Tile[Program.MAP_SCREEN_WIDTH, Program.MAP_SCREEN_HEIGHT];
            

            //PopulateLevel();

        }


        public void PopulateLevel()
        {
            p = pDungeon.pProgram.player;
            mlist = pDungeon.md.GenerateMonstersForLevel(LevelIndex, 5);

            for (int y = 0; y < Program.MAP_SCREEN_HEIGHT; y++)
            {
                for (int x = 0; x < Program.MAP_SCREEN_WIDTH; x++)
                {
                    try
                    {
                        Tile t = new Tile(x, y);
                        tiles[x, y] = t;
                        if (smap[y][x] == ' ')
                        {                            
                            OpenMonsterTiles.Add(t);
                            OpenItemTiles.Add(t);
                            OpenPersonTiles.Add(t);
                            OpenTerrainTiles.Add(t);
                        }

                        //if the tile is open, add it to the list of tiles available to receive objects (i.e., monsters, items, player, etc)


                    }
                    catch (Exception ex)
                    {
                        ex.ToString();
                    }
                }

            }
            
            PlaceMonsters();
            PlaceTerrain();
            PlaceItems();
        }

        public void PlacePlayer()
        {
            switch(p.TravelDir)
            {
                case 0:
                    p.x = dStairs.x;
                    p.y = dStairs.y;
                    break;
                case 1:
                    p.x = uStairs.x;
                    p.y = uStairs.y;
                    break;
                case 2:
                    int sIndex = rnd(0, (OpenPersonTiles.Count - 1)); 
                    p.x = OpenPersonTiles[sIndex].x; 
                    p.y = OpenPersonTiles[sIndex].y; 
                    OpenPersonTiles.RemoveAt(sIndex); 
                    OpenMonsterTiles.RemoveAt(sIndex);
                    break;
                default:
                    int rIndex = rnd(0, (OpenPersonTiles.Count - 1));
                    p.x = OpenPersonTiles[rIndex].x;
                    p.y = OpenPersonTiles[rIndex].y;
                    OpenPersonTiles.RemoveAt(rIndex);
                    OpenMonsterTiles.RemoveAt(rIndex);
                    break;
            }
                    
        } 

        public void PlaceTerrain()
        {
            //Place stairs          

            if (uStairs != null)
            {
                int tIndex = rnd(0, (OpenTerrainTiles.Count - 1));
                uStairs.x = OpenTerrainTiles[tIndex].x;
                uStairs.y = OpenTerrainTiles[tIndex].y;
                OpenTerrainTiles.RemoveAt(tIndex);
                OpenItemTiles.RemoveAt(tIndex);
            }
 
            if (dStairs != null)
            {
                int tIndex = rnd(0, (OpenTerrainTiles.Count - 1));
                dStairs.x = OpenTerrainTiles[tIndex].x;
                dStairs.y = OpenTerrainTiles[tIndex].y;
                OpenTerrainTiles.RemoveAt(tIndex);
                OpenItemTiles.RemoveAt(tIndex);
            }

        }

        private void PlaceItems()
        {
            foreach (Item i in iList)
            {
                int rIndex = rnd(0, (OpenItemTiles.Count - 1));
                i.x = OpenItemTiles[rIndex].x;
                i.y = OpenItemTiles[rIndex].y;
            }
        }

        private void PlaceMonsters()
        {
            foreach (Monster m in mlist)
            {
                int rIndex = rnd(0, (OpenMonsterTiles.Count - 1));
                m.x = OpenMonsterTiles[rIndex].x;
                m.y = OpenMonsterTiles[rIndex].y;
                OpenMonsterTiles.RemoveAt(rIndex);
                OpenPersonTiles.RemoveAt(rIndex);
            }
        }
        string[] ConvertMap(char[,] m)
        {
            string[] tm = new string[Program.MAP_SCREEN_HEIGHT];
            string l = string.Empty;
            
            for(int y = 0; y < Program.MAP_SCREEN_HEIGHT; y++)
            {
                for(int x = 0; x < Program.MAP_SCREEN_WIDTH; x++)
                {
                    try
                    {
                        l = l + m[x, y];
                    }
                    catch (Exception ex)
                    {
                        ex.ToString();
                    }
                }
                tm[y] = l;
                l = string.Empty;
            }
            return tm;
        }

        #region helpers



        void MaintTileArray(int ox, int oy, Monster m)
        {
            tiles[ox, oy] = tiles[ox, oy].RemoveMonster();
            tiles[m.x, m.y].m = m;
        }

        void MaintTileArray(int ox, int oy, Monster m, bool DeadMonster)
        {
            tiles[ox, oy] = tiles[ox, oy].RemoveMonster();

        }

        void KillMonster(Tile t)
        {
            mlist.Remove(t.m);
            MaintTileArray(t.x, t.y, t.m, true);
            pDungeon.pProgram.mapConsole.PutChar(t.x, t.y, ' ', Background.None);
            
        }


        int rnd()
        {
            int r = pDungeon.pProgram.rand.GetRandomInt(1, 10);
            return r;
        }

        int rnd(int min, int max)
        {
            int r = pDungeon.pProgram.rand.GetRandomInt(min, max);
            return r;
        }

        int Combat(int a_atk, int d_def)
        {
            int finalDamage;
            double damage = rnd() * (a_atk / 4);
            double dealt_damage = damage * (1.0f / (rnd() * (d_def / 4)));
            finalDamage = int.Parse(Math.Round(dealt_damage, MidpointRounding.AwayFromZero).ToString());
            return finalDamage;
        }

        bool IsPlayerThere(int y, int x)
        {
            bool playerThere = false;
            if (y == pDungeon.pProgram.player.y && x == pDungeon.pProgram.player.x)
            {
                playerThere = true;
            }
            return playerThere;
        }

        bool IsMonsterThere(int y, int x)
        {
            bool monsterThere = false;
            /*foreach(Monster m in mlist)
            {
                if(m.x == x && m.y == y)
                {
                    monsterThere = true;
                    break;
                }
            }*/
            if (tiles[x, y].m != null)
            {
                monsterThere = true;
            }
            return monsterThere;

        }
        #endregion

        public char OldTileDisplay(int x, int y)
        {
            char displayChar;
            if (tiles[x, y].t != null)
                displayChar = tiles[x, y].t.icon;
            else
                displayChar = ' ';

            return displayChar;
        }



        public void render_level(bool first, KeyPress key)
        {
            if (map == null)
            {    
                // initialize the map for the fov toolkit
                map = new TCODFov(Program.MAP_SCREEN_WIDTH, Program.MAP_SCREEN_HEIGHT);
                for (int y = 0; y < Program.MAP_SCREEN_HEIGHT; y++)
                {
                    for (int x = 0; x < Program.MAP_SCREEN_WIDTH; x++)
                    {
                        try
                        {
                            //Tile t = new Tile(x, y);
                            //tiles[x, y] = t;
                            if (smap[y][x] == ' ')
                            {
                                map.SetCell(x, y, true, true);// ground

                            }
                            else if (smap[y][x] == '=')
                            {
                                map.SetCell(x, y, true, false); // window
                            }
                            
                            //tiles[x, y] = new Tile(x, y);

                            //if the tile is open, add it to the list of tiles available to receive objects (i.e., monsters, items, player, etc)
   
                            
                        }
                        catch (Exception ex)
                        {
                            ex.ToString();
                        }
                    }
                }
                // 1d noise used for the torch flickering
                map_noise = new TCODNoise(1);
            }
            pDungeon.pProgram.mapConsole.PrintLine("DLev: " + p.CurrentLevelIndex + " " +  p.x.ToString() + "/" + p.y.ToString() + " | " + (dStairs != null ? dStairs.x.ToString() : "null") + "/" + (dStairs != null ? dStairs.y.ToString() : "null") + " | " + (uStairs != null ? uStairs.x.ToString() : "null") + "/" + (uStairs != null ? uStairs.y.ToString() : "null"), 1, 1, LineAlignment.Left);
            if (first)
            {
                TCODSystem.FPS = 30; // fps limited to 30
                // we draw the foreground only the first time.
                // during the pDungeon.pProgram.player movement, only the @ is redrawn.
                // the rest impacts only the background color
                // draw the help text & pDungeon.pProgram.player @
                pDungeon.pProgram.mapConsole.Clear();                
                pDungeon.pProgram.mapConsole.ForegroundColor = (ColorPresets.White);
                //pDungeon.pProgram.mapConsole.PrintLine("IJKL : move around\nT : torch fx " + (torch ? "off" : "on ") + " : light walls " + (light_walls ? "off" : "on ") + "\n+-: algo " + algo_names[algonum], 1, 1, LineAlignment.Left);
                //pDungeon.pProgram.mapConsole.ForegroundColor = (ColorPresets.Black);
                pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon);
                                
                //Place Monsters on map
                map.CalculateFOV(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.vision, light_walls, (FovAlgorithm)algonum);
                foreach (Monster m in mlist)
                {
                    //Can pDungeon.pProgram.player see monster?
                    bool pmvisible = map.CheckTileFOV(m.x, m.y);
                    if (pmvisible)
                    {
                        pDungeon.pProgram.mapConsole.PutChar(m.x, m.y, m.icon, Background.None);
                    }
                    else
                    {
                        pDungeon.pProgram.mapConsole.PutChar(m.x, m.y, ' ', Background.None);
                    }
                    try
                    {
                        tiles[m.x, m.y].m = m;
                    }
                    catch (Exception ex)
                    {
                        ex.ToString();
                    }
                }

                //place terrain on map
                foreach (Terrain t in tList)
                {
                    //Can plaeyer see terrain?
                    bool pmvisible = map.CheckTileFOV(t.x, t.y);
                    if (pmvisible)
                    {
                        if(t.x != p.x && t.y != p.y)
                            pDungeon.pProgram.mapConsole.PutChar(t.x, t.y, t.icon, Background.None);
                    }
                    else
                    {
                        pDungeon.pProgram.mapConsole.PutChar(t.x, t.y, ' ', Background.None);
                    }
                    try
                    {
                        tiles[t.x, t.y].t = t;
                    }
                    catch (Exception ex)
                    {
                        ex.ToString();
                    }
                }

                //place items on map
                foreach (Item i in iList)
                {
                    //Can plaeyer see terrain?
                    bool pmvisible = map.CheckTileFOV(i.x, i.y);
                    if (pmvisible)
                    {
                        if (i.x != p.x && i.y != p.y)
                            pDungeon.pProgram.mapConsole.PutChar(i.x, i.y, i.icon, Background.None);
                    }
                    else
                    {
                        pDungeon.pProgram.mapConsole.PutChar(i.x, i.y, ' ', Background.None);
                    }
                    try
                    {
                        tiles[i.x, i.y].items.Add(i);
                    }
                    catch (Exception ex)
                    {
                        ex.ToString();
                    }
                }


                // draw windows
                for (int y = 0; y < Program.MAP_SCREEN_HEIGHT; y++)
                {
                    for (int x = 0; x < Program.MAP_SCREEN_WIDTH; x++)
                    {
                        if (smap[y][x] == '=')
                        {
                            pDungeon.pProgram.mapConsole.PutChar(x, y, '=');
                        }
                    }
                }
                recalculatePath = true;
            }

            if (recomputeFov)
            {
                // calculate the field of view from the pDungeon.pProgram.player position
                recomputeFov = false;
                map.CalculateFOV(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.vision, light_walls, (FovAlgorithm)algonum);
            }
            // torch position & intensity variation
            float dx = 0.0f, dy = 0.0f, di = 0.0f;
            if (torch)
            {
                // slightly change the perlin noise parameter
                torchx += 0.2f;
                // randomize the light position between -1.5 and 1.5
                float[] tdx = { torchx + 20.0f };
                dx = map_noise.GetPerlinNoise(tdx) * 1.5f;
                tdx[0] += 30.0f;
                dy = map_noise.GetPerlinNoise(tdx) * 1.5f;
                // randomize the light intensity between -0.2 and 0.2
                float[] torchxArray = { torchx };
                di = 0.2f * map_noise.GetPerlinNoise(torchxArray);
            }

            // draw the dungeon
            for (int y = 0; y < Program.MAP_SCREEN_HEIGHT; y++)
            {
                for (int x = 0; x < Program.MAP_SCREEN_WIDTH; x++)
                {
                    bool visible = map.CheckTileFOV(x, y);
                    bool wall = (smap[y][x] == '#');
                    if (!visible)
                    {
                        if (MapVisible)
                        {
                            pDungeon.pProgram.mapConsole.SetCharBackground(x, y, (wall ? darkWall : darkGround), Background.Set);
                        }
                    }
                    else
                    {
                        
                        Color cellColor = wall ? seenWall : seenGround;

                        /*
                        // torch flickering fx
                        Color baseColor = wall ? darkWall : darkGround;
                        Color light = wall ? lightWall : lightGround;
                        // cell distance to torch (squared)
                        float r = (float)((x - pDungeon.pProgram.player.x + dx) * (x - pDungeon.pProgram.player.x + dx) + (y - pDungeon.pProgram.player.y + dy) * (y - pDungeon.pProgram.player.y + dy));
                        if (r < SQUARED_TORCH_RADIUS)
                        {
                            // l = 1.0 at pDungeon.pProgram.player position, 0.0 at a radius of 10 cells
                            float l = (SQUARED_TORCH_RADIUS - r) / SQUARED_TORCH_RADIUS + di;
                            // clamp between 0 and 1
                            if (l < 0.0f)
                                l = 0.0f;
                            else if (l > 1.0f)
                                l = 1.0f;
                            // interpolate the color
                            baseColor = Color.FromRGB((byte)(baseColor.Red + (light.Red - baseColor.Red) * l),
                                                (byte)(baseColor.Green + (light.Green - baseColor.Green) * l),
                                                (byte)(baseColor.Blue + (light.Blue - baseColor.Blue) * l));
                        }
                        pDungeon.pProgram.mapConsole.SetCharBackground(x, y, baseColor, Background.Set);
                         */
                        pDungeon.pProgram.mapConsole.SetCharBackground(x, y, cellColor, Background.Set);

                    }
                }
            }

            //Debugging - currently, must put break in code at line within if statement
            if (key.Character == 'D')
            {
                bool debug = true;
            }
            else if (key.KeyCode == KeyCode.TCODK_KP8)
            {
                MovePlayerNorth();
            }

            else if (key.KeyCode == KeyCode.TCODK_KP9)
            {
                MovePlayerNorthEast();
            }

            else if (key.KeyCode == KeyCode.TCODK_KP7)
            {
                // pDungeon.pProgram.player move north west
                MovePlayerNorthWest();

            }
            else if (key.KeyCode == KeyCode.TCODK_KP2)
            {
                //south
                MovePlayerSouth();
            }

            else if (key.KeyCode == KeyCode.TCODK_KP3)
            {
                //se
                MovePlayerSouthEast();
            }

            else if (key.KeyCode == KeyCode.TCODK_KP1)
            {
                //sw
                MovePlayerSouthWest();
            }

            else if (key.KeyCode == KeyCode.TCODK_KP4)
            {
                //w
                MovePlayerWest();
            }
            else if (key.KeyCode == KeyCode.TCODK_KP6)
            {
                //e
                MovePlayerEast();
            }
            //Going Down a level
            else if (key.Character == '>' && dStairs != null)
            {
                if (dStairs.x == p.x && dStairs.y == p.y)
                {
                    p.CurrentLevelIndex++;
                    p.x = pDungeon.Levels[p.CurrentLevelIndex].uStairs.x;
                    p.y = pDungeon.Levels[p.CurrentLevelIndex].uStairs.y;
                }
            }
            //Going up a level
            else if (key.Character == '<' && uStairs != null)
            {
                if (uStairs.x == p.x && uStairs.y == p.y)
                {
                    p.CurrentLevelIndex--;
                    p.x = pDungeon.Levels[p.CurrentLevelIndex].dStairs.x;
                    p.y = pDungeon.Levels[p.CurrentLevelIndex].dStairs.y;
                }
            }
            else if (key.Character == 'V')
            {
                MapVisible = !MapVisible ? true : false;
            }

            //Handle Dead Monsters


            //move monster
            if (recomputeFov)
            {
                foreach (Terrain t in tList)
                {
                    map.CalculateFOV(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.vision, false, (FovAlgorithm)algonum);
                    bool PlayerSeesTerrain = map.CheckTileFOV(t.x, t.y);

                    if (PlayerSeesTerrain)
                    {
                        if(!IsPlayerThere(t.y, t.x))
                            pDungeon.pProgram.mapConsole.PutChar(t.x, t.y, t.icon, Background.None);                        
                    }
                }

                foreach (Item i in iList)
                {
                    map.CalculateFOV(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.vision, false, (FovAlgorithm)algonum);
                    bool PlayerSeesItem = map.CheckTileFOV(i.x, i.y);

                    if (PlayerSeesItem)
                    {
                        if (!IsPlayerThere(i.y, i.x) && i.OnMap)
                            pDungeon.pProgram.mapConsole.PutChar(i.x, i.y, i.icon, Background.None);
                    }
                    
                }

                foreach (Monster m in mlist)
                {
                    if (recalculatePath)
                    {
                        int curX = m.x, cury = m.y;
                        //Can player see monster?
                        map.CalculateFOV(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.vision, false, (FovAlgorithm)algonum);
                        bool PlayerSeesMonster = map.CheckTileFOV(m.x, m.y);

                        //can monster see pDungeon.pProgram.player?
                        map.CalculateFOV(m.x, m.y, m.vision, false, (FovAlgorithm)algonum);
                        bool MonsterSeesPlayer = map.CheckTileFOV(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y);

                        //find path
                        //TODO:  Investigate diagonal cost (prev value 1.41)
                        path = new TCODPathFinding(map, 1.41);
                        path.ComputePath(m.x, m.y, pDungeon.pProgram.player.x, pDungeon.pProgram.player.y);
                        
                        if (PlayerSeesMonster && MonsterSeesPlayer && !path.IsPathEmpty())
                        {


                            pDungeon.pProgram.mapConsole.PutChar(m.x, m.y, OldTileDisplay(m.x, m.y), Background.None);
                            path.WalkPath(ref m.x, ref m.y, true);
                            if (!(IsPlayerThere(m.y, m.x)))
                            {
                                pDungeon.pProgram.mapConsole.PutChar(m.x, m.y, m.icon, Background.None);
                                pDungeon.pProgram.WriteToLog("Player sees " + m.name + ".  " + m.name + " sees player");
                            }
                            else
                            {
                                m.x = curX;
                                m.y = cury;
                                pDungeon.pProgram.mapConsole.PutChar(m.x, m.y, m.icon, Background.None);
                                int damage = Combat(pDungeon.pProgram.player.atk, m.def);
                                pDungeon.pProgram.WriteToLog(m.name + " Attacks Player (" + pDungeon.pProgram.player.hp + " hp).  Damage done:" + damage.ToString());
                                pDungeon.pProgram.player.hp -= damage;
                            }

                        }
                        else if (PlayerSeesMonster && !MonsterSeesPlayer && !path.IsPathEmpty())
                        {
                            pDungeon.pProgram.mapConsole.PutChar(m.x, m.y, m.icon, Background.None);
                            pDungeon.pProgram.WriteToLog("Player can see " + m.name + ".  " + m.name + " can't see Player");


                        }
                        else if (!PlayerSeesMonster && MonsterSeesPlayer && !path.IsPathEmpty())
                        {
                            path.WalkPath(ref m.x, ref m.y, true);
                            pDungeon.pProgram.WriteToLog("Player can't see see " + m.name + ".  " + m.name + " sees Player");
                        }
                        else if (!PlayerSeesMonster && !MonsterSeesPlayer && !path.IsPathEmpty())
                        {
                            //do nothing for now
                            pDungeon.pProgram.mapConsole.PutChar(m.x, m.y, ' ', Background.None);
                            //pDungeon.pProgram.WriteToLog("Player can't see " + m.name + ".  " + m.name + " can't see Player");
                        }
                        MaintTileArray(curX, cury, m);

                    }

                }
                recalculatePath = false;
            }
        }


        void MovePlayerNorth()
        {
            if (!pDungeon.ComplexCommand)
            {
                if (smap[pDungeon.pProgram.player.y - 1][pDungeon.pProgram.player.x] == ' ' && !IsMonsterThere((pDungeon.pProgram.player.y - 1), pDungeon.pProgram.player.x))
                {
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, OldTileDisplay(p.x, p.y), Background.None);
                    pDungeon.pProgram.player.y--;
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon, Background.None);
                    recomputeFov = true;
                    recalculatePath = true;

                }
                else if (IsMonsterThere((pDungeon.pProgram.player.y - 1), pDungeon.pProgram.player.x))
                {

                    int damage = Combat(pDungeon.pProgram.player.atk, tiles[(pDungeon.pProgram.player.x), (pDungeon.pProgram.player.y - 1)].m.def);

                    pDungeon.pProgram.WriteToLog("pDungeon.pProgram.player Attacks " + tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y - 1)].m.name + "(" + tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y - 1)].m.hp + " hp.  Damage done:" + damage.ToString());
                    tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y - 1)].m.hp -= damage;

                    if (tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y - 1)].m.hp <= 0)
                        KillMonster(tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y - 1)]);

                    recomputeFov = true;
                    recalculatePath = true;
                }
            }
        }

        void MovePlayerNorthEast()
        {
            if (!pDungeon.ComplexCommand)
            {
                // pDungeon.pProgram.player move north east
                if (smap[pDungeon.pProgram.player.y - 1][pDungeon.pProgram.player.x + 1] == ' ' && !IsMonsterThere((pDungeon.pProgram.player.y - 1), (pDungeon.pProgram.player.x + 1)))
                {

                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, OldTileDisplay(p.x, p.y), Background.None);
                    pDungeon.pProgram.player.y--;
                    pDungeon.pProgram.player.x++;
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon, Background.None);
                    recomputeFov = true;
                    recalculatePath = true;
                }
                else if (IsMonsterThere((pDungeon.pProgram.player.y - 1), (pDungeon.pProgram.player.x + 1)))
                {

                    int damage = Combat(pDungeon.pProgram.player.atk, tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y - 1)].m.def);

                    pDungeon.pProgram.WriteToLog("pDungeon.pProgram.player Attacks " + tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y - 1)].m.name + "(" + tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y - 1)].m.hp + " hp.  Damage done:" + damage.ToString());
                    tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y - 1)].m.hp -= damage;

                    if (tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y - 1)].m.hp <= 0)
                        KillMonster(tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y - 1)]);


                    recomputeFov = true;
                    recalculatePath = true;
                }
            }
        }

        void MovePlayerNorthWest()
        {
            if (!pDungeon.ComplexCommand)
            {
                if (smap[pDungeon.pProgram.player.y - 1][pDungeon.pProgram.player.x - 1] == ' ' && !IsMonsterThere((pDungeon.pProgram.player.y - 1), (pDungeon.pProgram.player.x - 1)))
                {
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, OldTileDisplay(p.x, p.y), Background.None);
                    pDungeon.pProgram.player.y--;
                    pDungeon.pProgram.player.x--;
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon, Background.None);
                    recomputeFov = true;
                    recalculatePath = true;
                }
                else if (IsMonsterThere((pDungeon.pProgram.player.y - 1), (pDungeon.pProgram.player.x - 1)))
                {

                    int damage = Combat(pDungeon.pProgram.player.atk, tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y - 1)].m.def);

                    pDungeon.pProgram.WriteToLog("pDungeon.pProgram.player Attacks " + tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y - 1)].m.name + "(" + tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y - 1)].m.hp + " hp.  Damage done:" + damage.ToString());
                    tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y - 1)].m.hp -= damage;

                    if (tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y - 1)].m.hp <= 0)
                        KillMonster(tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y - 1)]);


                    recomputeFov = true;
                    recalculatePath = true;
                }
            }
        }

        void MovePlayerEast()
        {
            if (!pDungeon.ComplexCommand)
            {
                // pDungeon.pProgram.player move east
                if (smap[pDungeon.pProgram.player.y][pDungeon.pProgram.player.x + 1] == ' ' && !IsMonsterThere(pDungeon.pProgram.player.y, (pDungeon.pProgram.player.x + 1)))
                {
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, OldTileDisplay(p.x, p.y), Background.None);
                    pDungeon.pProgram.player.x++;
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon, Background.None);
                    recomputeFov = true;
                    recalculatePath = true;
                }
                else if (IsMonsterThere(pDungeon.pProgram.player.y, (pDungeon.pProgram.player.x + 1)))
                {
                    int damage = Combat(pDungeon.pProgram.player.atk, tiles[(pDungeon.pProgram.player.x + 1), pDungeon.pProgram.player.y].m.def);

                    pDungeon.pProgram.WriteToLog("Player Attacks " + tiles[(pDungeon.pProgram.player.x + 1), pDungeon.pProgram.player.y].m.name + "(" + tiles[(pDungeon.pProgram.player.x + 1), pDungeon.pProgram.player.y].m.hp + " hp.  Damage done:" + damage.ToString());
                    tiles[(pDungeon.pProgram.player.x + 1), pDungeon.pProgram.player.y].m.hp -= damage;

                    if (tiles[(pDungeon.pProgram.player.x + 1), pDungeon.pProgram.player.y].m.hp <= 0)
                        KillMonster(tiles[(pDungeon.pProgram.player.x + 1), pDungeon.pProgram.player.y]);

                    recomputeFov = true;
                    recalculatePath = true;
                }
            }
        }

        void MovePlayerWest()
        {
            if (!pDungeon.ComplexCommand)
            {
                // pDungeon.pProgram.player move west
                if (smap[pDungeon.pProgram.player.y][pDungeon.pProgram.player.x - 1] == ' ' && !IsMonsterThere(pDungeon.pProgram.player.y, (pDungeon.pProgram.player.x - 1)))
                {
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, OldTileDisplay(p.x, p.y), Background.None);
                    pDungeon.pProgram.player.x--;
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon, Background.None);
                    recomputeFov = true;
                    recalculatePath = true;
                }
                else if (IsMonsterThere(pDungeon.pProgram.player.y, (pDungeon.pProgram.player.x - 1)))
                {
                    int damage = Combat(pDungeon.pProgram.player.atk, tiles[(pDungeon.pProgram.player.x - 1), pDungeon.pProgram.player.y].m.def);

                    pDungeon.pProgram.WriteToLog("pDungeon.pProgram.player Attacks " + tiles[(pDungeon.pProgram.player.x - 1), pDungeon.pProgram.player.y].m.name + "(" + tiles[(pDungeon.pProgram.player.x - 1), pDungeon.pProgram.player.y].m.hp + " hp.  Damage done:" + damage.ToString());
                    tiles[(pDungeon.pProgram.player.x - 1), pDungeon.pProgram.player.y].m.hp -= damage;

                    if (tiles[(pDungeon.pProgram.player.x - 1), pDungeon.pProgram.player.y].m.hp <= 0)
                        KillMonster(tiles[(pDungeon.pProgram.player.x - 1), pDungeon.pProgram.player.y]);
                    recomputeFov = true;
                    recalculatePath = true;
                }
            }
        }

        void MovePlayerSouthWest()
        {
            if (!pDungeon.ComplexCommand)
            {
                // pDungeon.pProgram.player move south west
                if (smap[pDungeon.pProgram.player.y + 1][pDungeon.pProgram.player.x - 1] == ' ' && !IsMonsterThere((pDungeon.pProgram.player.y + 1), (pDungeon.pProgram.player.x - 1)))
                {
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, OldTileDisplay(p.x, p.y), Background.None);
                    pDungeon.pProgram.player.y++;
                    pDungeon.pProgram.player.x--;
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon, Background.None);
                    recomputeFov = true;
                    recalculatePath = true;
                }
                else if (IsMonsterThere((pDungeon.pProgram.player.y + 1), (pDungeon.pProgram.player.x - 1)))
                {

                    int damage = Combat(pDungeon.pProgram.player.atk, tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y + 1)].m.def);

                    pDungeon.pProgram.WriteToLog("pDungeon.pProgram.player Attacks " + tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y + 1)].m.name + "(" + tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y + 1)].m.hp + " hp.  Damage done:" + damage.ToString());
                    tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y + 1)].m.hp -= damage;

                    if (tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y + 1)].m.hp <= 0)
                        KillMonster(tiles[(pDungeon.pProgram.player.x - 1), (pDungeon.pProgram.player.y + 1)]);


                    recomputeFov = true;
                    recalculatePath = true;
                }
            }
        }

        void MovePlayerSouthEast()
        {
            if (!pDungeon.ComplexCommand)
            {
                // pDungeon.pProgram.player move south east
                if (smap[pDungeon.pProgram.player.y + 1][pDungeon.pProgram.player.x + 1] == ' ' && !IsMonsterThere((pDungeon.pProgram.player.y + 1), (pDungeon.pProgram.player.x + 1)))
                {
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, OldTileDisplay(p.x, p.y), Background.None);
                    pDungeon.pProgram.player.y++;
                    pDungeon.pProgram.player.x++;
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon, Background.None);
                    recomputeFov = true;
                    recalculatePath = true;
                }
                else if (IsMonsterThere((pDungeon.pProgram.player.y + 1), (pDungeon.pProgram.player.x + 1)))
                {

                    int damage = Combat(pDungeon.pProgram.player.atk, tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y + 1)].m.def);

                    pDungeon.pProgram.WriteToLog("pDungeon.pProgram.player Attacks " + tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y + 1)].m.name + "(" + tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y + 1)].m.hp + " hp.  Damage done:" + damage.ToString());
                    tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y + 1)].m.hp -= damage;

                    if (tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y + 1)].m.hp <= 0)
                        KillMonster(tiles[(pDungeon.pProgram.player.x + 1), (pDungeon.pProgram.player.y + 1)]);


                    recomputeFov = true;
                    recalculatePath = true;
                }
            }
        }

        void MovePlayerSouth()
        {
            if (!pDungeon.ComplexCommand)
            {
                // pDungeon.pProgram.player move south
                if (smap[pDungeon.pProgram.player.y + 1][pDungeon.pProgram.player.x] == ' ' && !IsMonsterThere((pDungeon.pProgram.player.y + 1), pDungeon.pProgram.player.x))
                {
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, OldTileDisplay(p.x, p.y), Background.None);
                    pDungeon.pProgram.player.y++;
                    pDungeon.pProgram.mapConsole.PutChar(pDungeon.pProgram.player.x, pDungeon.pProgram.player.y, pDungeon.pProgram.player.icon, Background.None);
                    recomputeFov = true;
                    recalculatePath = true;
                }
                else if (IsMonsterThere((pDungeon.pProgram.player.y + 1), pDungeon.pProgram.player.x))
                {

                    int damage = Combat(pDungeon.pProgram.player.atk, tiles[(pDungeon.pProgram.player.x), (pDungeon.pProgram.player.y + 1)].m.def);

                    pDungeon.pProgram.WriteToLog("pDungeon.pProgram.player Attacks " + tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y + 1)].m.name + "(" + tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y + 1)].m.hp + " hp.  Damage done:" + damage.ToString());
                    tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y + 1)].m.hp -= damage;

                    if (tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y + 1)].m.hp <= 0)
                        KillMonster(tiles[pDungeon.pProgram.player.x, (pDungeon.pProgram.player.y + 1)]);


                    recomputeFov = true;
                    recalculatePath = true;
                }
            }
        }

    }
}
